/**
 * 定义Schema
 * 他相当于MongoDB数据库的一个映射。Schema是一种以文件形式存储的数据库模型骨架，无法直接通往数据库端，也就是说它不具备对数据库的操作能力。
 * Schema是以key-value形式Json格式的数据。
 *
 *
 * Schema中的数据类型
 *
  *   String ：字符串类型
      Number ：数字类型
      Date ： 日期类型
      Boolean： 布尔类型
      Buffer ： NodeJS buffer 类型
      ObjectID ： 主键,一种特殊而且非常重要的类型  (可以这么理解，是mongodb里面的每条数据里面的 _id这个值吧)
      Mixed ：混合类型
      Array ：集合类型


  Mongoose中的三个概念
  schema ：用来定义表的模版，实现和MongoDB数据库的映射。用来实现每个字段的类型，长度，映射的字段，不具备表的操作能力。
  model ：具备某张表操作能力的一个集合，是mongoose的核心能力。我们说的模型就是这个Mondel。
  entity ：类似记录，由Model创建的实体，也具有影响数据库的操作能力。


  Mongoose中的三个概念（自己的理解）
  schema： 定义表模板，也就是定义规则，里面的值等，你要用和我定义的一样，否则会给你报错, 是一个json对象的形式
  model ： 根据schema模板，写入数据，然后插入等操作，具有操作数据库的能力
  entity： 和model一样
  注意： 他们三个都是在mongoose里面的东西
 */

//  初学定义一个用户schema
 const mongoose = require('mongoose') //引入mongoose
 const Schema = mongoose.Schema  //声明Schema
 let ObjectId = Schema.Types.ObjectId  //声明Object类型  个人理解： _id的的那种值

//  加密,引入bcrypt模块
 const bcrypt = require('bcrypt') //bcrypt是一种跨平台的文件加密工具
 let SALT_WORK_FACTOR = 10 //加密的强度，bcrypt强度等级1-10， 其中1-3为最低，系统会认为强度过低，会使用10给，这里我们直接使用10，等级越高，耗时越久

//  创建我么德用户Schema
const userSchema = new Schema({
  UserId:ObjectId,
  userName:{unique:true,type:String}, //unique唯一的意思
  password:String, //这里直接写String，暂时理解为如果只有一个要求，则不用对象方式写规则，直接写
  createAt:{type:Date,default:new Date()}, //创建用户日期
  lastLoginAt:{type:Date,default:new Date()}, //最后登录时间
},{
  collection:'users'  //存储在哪个集合,指定集合
})

// 每次存储数据前时都要执行需要加盐加密（因为这里涉及到了一个密码，不能存明文）
// // 使用pre中间件在用户信息存储前进行密码加密
userSchema.pre('save',function (next) {  // 如何理解pre 想到于vue里面的路由拦截， 你要插入数据，必须先走我这个中间件，才能继续下去，否则是不行的
  // let user = this; //这个this包含的就是上面的userSchema里面对象的东西
  // 进行加密（加盐）
  bcrypt.genSalt(SALT_WORK_FACTOR, (err,salt)=>{
    if(err) return next(err)
    bcrypt.hash(this.password,salt,(err,hash)=>{
      this.password = hash;
      next();
    })
  })
})

// 对比加盐加密后的密码，提供给登录的时候用
userSchema.methods={
  // 密码对比的方法
  comparePassword:(_password,password)=>{ //客户端密码，一个是数据库取出来的密码
    return new Promise((reslove,reject)=>{  //bcrypt提供的compare方法就可以比对，最后包装成Promise返回就可以了
      bcrypt.compare(_password,password,(err,isMatch)=>{
        if(!err) reslove(isMatch)
        else reject(err)
      })
    })
  }
}

// 发布模型
mongoose.model('User',userSchema)


// 特别解释：
/**
 * 模型建好了，什么时候用，怎么用，在哪用
 * 什么时候用： 在后台服务已启动好的时候用，也就是在init里面用
 * 怎么用： 看init.js文件，导入模型 需安装npm i glob这个包， node的glob模块允许你使用 * 等符号，来写一个glob规则，
 * 在哪用： 最后的使用和怎么用，都是同个意思了， 导入，然后就可以再index.js里面插入和差数据等
 * */
